package com.atguigu.security.component;

import cn.hutool.core.bean.BeanUtil;
import com.atguigu.security.pojo.vo.UserRolePermVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Jungle
 * @create 2024-01-17 22:38  //来定义如何去数据库中按照用户名查询用户
 */
@Slf4j
@Component
public class AppReactiveUserDetailsService implements ReactiveUserDetailsService {

    @Autowired
    private DatabaseClient databaseClient;
    @Autowired
    private PasswordEncoder encoder;

    // 自定义如何按照用户名取数据库查询用户信息
    @Override
    public Mono<UserDetails> findByUsername(String username) {
        return databaseClient.sql("SELECT u.*,r.id rId,r.`name` rName,r.`value` rValue,p.id pId,p.`value` pValue,p.uri pUri,p.description pDesc FROM t_user u LEFT JOIN t_user_role ur ON ur.user_id=u.id LEFT JOIN t_roles r ON r.id=ur.role_id LEFT JOIN t_role_perm rp ON rp.role_id=r.id LEFT JOIN t_perm p ON p.id=rp.perm_id WHERE u.username=?")
                .bind(0, username)
                .fetch()
                .all()
                .bufferUntilChanged(rowMap -> Long.parseLong(String.valueOf(rowMap.get("id"))))
                .map(list -> BeanUtil.copyToList(list, UserRolePermVO.class))
                .map(vos -> {
                    // 根据权限分组
                    Map<String, List<UserRolePermVO>> pGroup = vos.stream().collect(Collectors.groupingBy(UserRolePermVO::getPValue));
                    // 根据角色进行分组
                    Map<String, List<UserRolePermVO>> rGroup = vos.stream().collect(Collectors.groupingBy(UserRolePermVO::getRValue));
                    return User.builder()
                            .username(username)
                            .password(vos.get(0).getPassword())
                            // .passwordEncoder(encoder::encode)
                            .authorities(pGroup.keySet().stream().map(SimpleGrantedAuthority::new).toList())
                            .roles(rGroup.keySet().toArray(String[]::new))
                            .build();
                }).next();
    }

}

